#ifndef K_THREAD_H
#define K_THREAD_H
#pragma once

#include "K_Windows.h"
#include "KAutoPtr.h"

class KThread : KNoCopy {
public:
    KThread();
    virtual ~KThread();
public:
    DWORD           exitCode() const;
    bool            isFinished() const  { return !isRunning(); }
    bool            isRunning() const;
    int             priority() const;
    bool            setPriority(int nPriority = THREAD_PRIORITY_NORMAL);
public:
    virtual void    exit(DWORD ret)     { TerminateThread(m_thread, ret); }
    bool            join()              { return wait(INFINITE); }
    void            quit()              { KThread::exit(0); }
    virtual void    start();
    bool            wait(DWORD ms);
    template <class DerivedT, size_t N>
    static bool     waitAll(DerivedT (&threads)[N], DWORD ms);
    template <class DerivedT>
    static bool     waitAll(DerivedT *threads, size_t n, DWORD ms);
protected:
    // Thread working procedure
    virtual DWORD run() = 0;
private:
    static unsigned WINAPI ThreadProc(void *lpThread);
private:
    HANDLE  m_thread;
    int     m_priority;
};

template <class DerivedT, size_t N>
bool KThread::waitAll(DerivedT (&threads)[N], DWORD ms)
{
    return waitAll(threads, N, ms);
}

template <class DerivedT>
bool KThread::waitAll(DerivedT *threads, size_t n, DWORD ms)
{
    KAutoPtr<HANDLE, true> hThreads(new HANDLE[n]);
    size_t c = 0;
    while (n--) {
        if (threads[n].m_thread) {
            hThreads[c++] = threads[n].m_thread;
        }
    }
    if (c > 0) {
        return WaitForMultipleObjects(c, hThreads, TRUE, ms) == WAIT_OBJECT_0;
    }
    return true;
}

#endif // K_THREAD_H